#ifndef EVAL_UPMC_H
#define EVAL_UPMC_H



/* ***
 * Several useful expression macro
 * ***/

#define IS_INTEGER(e) ((e)->type_expression == Integer)
#define INT_VALUE(e) ((e)->content.as_constant.int_value)
#define IS_INTEGER_X(e, x)					\
  (IS_INTEGER(e) && ((e)->content.as_constant.int_value == (x)))

#define IS_DOUBLE(e)  ((e)->type_expression == Double)
#define IS_DOUBLE_X(e, x)					\
  (IS_DOUBLE(e) && ((e)->content.as_constant.int_value == (x)))
#define DOUBLE_VALUE(e) ((e)->content.as_constant.double_value)

#define IS_ZERO(e)							\
  (IS_INTEGER(e) ? (INT_VALUE(e)    == 0) :				\
  IS_DOUBLE(e)  ? (DOUBLE_VALUE(e) == 0) :				\
		0)
#define IS_ONE(e)							\
  (IS_INTEGER(e) ? (INT_VALUE(e)    == 1) :				\
  IS_DOUBLE(e)  ? (DOUBLE_VALUE(e) == 1) :				\
   0)

#define IS_BINARY_OPERATION(e) ((e)->type_expression == BinaryOperation)
#define SYMBOL(e) ((e)->content.as_binary_operation.symbol)
#define LEFT(e) ((e)->content.as_binary_operation.left)
#define RIGHT(e) ((e)->content.as_binary_operation.right)
#define IS_ADDITION(e) (IS_BINARY_OPERATION(e) && (SYMBOL(e) == '+'))
#define IS_SUBSTRACTION(e) (IS_BINARY_OPERATION(e) && (SYMBOL(e) == '-'))
#define IS_MULTIPLICATION(e) (IS_BINARY_OPERATION(e) && (SYMBOL(e) == '*'))
#define IS_DIVISION(e) (IS_BINARY_OPERATION(e) && (SYMBOL(e) == '/'))



/* ***
 * The representation of an expression TP1 (Q4).
 * ***/
enum TypeExpression { Integer, Double, BinaryOperation };

typedef struct _Expression {

  enum TypeExpression type_expression;

  union _Content {
    struct _Constant {
      int int_value;
      double double_value;
    } as_constant;
    struct _BinaryOperation {
      char symbol;
      struct _Expression* left;
      struct _Expression* right;
    } as_binary_operation;
  } content;
} Expression;






/* ***
 * Hypothesis : no trailer blanck characters.
 *
 * cp : the next char in the command line. 
 * return 1 if the next command arg is a shellvar, else 0
 * ***/
int is_shellvar(char* cp);

/* ***
 *     cp : the next char in the command line. 
 * new_cp : if the next command arg is a shellvar, new_cp 
 *          will contains a pointer on the character following the 
 *          shellvar.
 * return : the interpreted value of the found shellvar, 
 *          or null if not found or an error occur. When null is
 *          return new-cp = cp
 * TP1 (Q3)
 * ***/
char* interpret_shellvar(char* cp, char** new_cp);

/* ***
 *
 * ***/
double eval(Expression* e);

/* ***
 * simplify an expresion according following rules :
 *  add : e+0 = 0+e = e, 
 *  sub : e-0 = e
 * mult : e*0 = 0*e = 0,   e*1 = 1*e = e 
 *  div : e/e = 1
 *
 * Arguments:
 * e : the expression to simplify
 * ***/
Expression* simplify(Expression* e);

/* ***
 *
 * ***/
Expression* new_integer(int i);

/* ***
 *
 * ***/
Expression* new_double(double b);

/* ***
 *
 * ***/
Expression* new_binary_operation(char symbol, Expression* left, Expression* right);

/* ***
 * Display an expression
 * e : the expression to display
 * ***/
void display_expression(Expression* e);

#endif /* EVAL_UPMC_H */
